package com.service;

import com.mapper.ConsumerMapper;
import com.pojo.requestjson.FaceRecognitionRequest;
import com.service.iter.IFaceServiceImpl;
import com.util.JsonParser;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLException;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 面部服务impl
 *
 * @author 蔡文欣
 * @date 2023/07/06 09:48:09
 */
@Service
@Transactional
public class FaceServiceImpl implements IFaceServiceImpl {

    /**
     * api密钥
     */
    private static final String API_KEY = "7Qd7y5LflV5udF7sVgS01MPzNLgeuTWA";
    /**
     * api秘密
     */
    private static final String API_SECRET = "jTxK14YcqHlLWdepWnnomTbzh_OkZGtc";
    /**
     * 连接时间
     */
    private final static int CONNECT_TIME_OUT = 30000;
    /**
     * 读出时间
     */
    private final static int READ_OUT_TIME = 50000;
    /**
     * 边界字符串
     */
    private static final String boundaryString = getBoundary();
    /**
     * rest模板
     */
    private final RestTemplate restTemplate;
    /**
     * faceset令牌
     */
    private String FACESET_TOKEN = "6fb273269547a289df384af6dbb54331";
    /**
     * 消费者映射器
     */
    @Autowired
    private ConsumerMapper consumerMapper;

    /**
     * 面部服务impl
     */
    public FaceServiceImpl() {
        this.restTemplate = new RestTemplate();
    }

    /**
     *
     * 提交
     *
     * @param url     url
     * @param map     地图
     * @param fileMap 文件映射
     * @return {@link byte[]}
     * @throws Exception 异常
     */
    protected static byte[] post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap) throws Exception {
        HttpURLConnection conne;
        URL url1 = new URL(url);
        conne = (HttpURLConnection) url1.openConnection();
        conne.setDoOutput(true);
        conne.setUseCaches(false);
        conne.setRequestMethod("POST");
        conne.setConnectTimeout(CONNECT_TIME_OUT);
        conne.setReadTimeout(READ_OUT_TIME);
        conne.setRequestProperty("accept", "*/*");
        conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
        conne.setRequestProperty("connection", "Keep-Alive");
        conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
        DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry) iter.next();
            String key = entry.getKey();
            String value = entry.getValue();
            obos.writeBytes("--" + boundaryString + "\r\n");
            obos.writeBytes("Content-Disposition: form-data; name=\"" + key
                    + "\"\r\n");
            obos.writeBytes("\r\n");
            obos.writeBytes(value + "\r\n");
        }
        if (fileMap != null && fileMap.size() > 0) {
            Iterator fileIter = fileMap.entrySet().iterator();
            while (fileIter.hasNext()) {
                Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
                obos.writeBytes("--" + boundaryString + "\r\n");
                obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey()
                        + "\"; filename=\"" + encode(" ") + "\"\r\n");
                obos.writeBytes("\r\n");
                obos.write(fileEntry.getValue());
                obos.writeBytes("\r\n");
            }
        }
        obos.writeBytes("--" + boundaryString + "--" + "\r\n");
        obos.writeBytes("\r\n");
        obos.flush();
        obos.close();
        InputStream ins = null;
        int code = conne.getResponseCode();
        try {
            if (code == 200) {
                ins = conne.getInputStream();
            } else {
                ins = conne.getErrorStream();
            }
        } catch (SSLException e) {
            e.printStackTrace();
            return new byte[0];
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        int len;
        while ((len = ins.read(buff)) != -1) {
            baos.write(buff, 0, len);
        }
        byte[] bytes = baos.toByteArray();
        ins.close();
        return bytes;
    }

    /**
     * 获取边界
     *
     * @return {@link String}
     */
    private static String getBoundary() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 32; ++i) {
            sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
        }
        return sb.toString();
    }

    /**
     * 编码
     *
     * @param value 值
     * @return {@link String}
     * @throws Exception 异常
     */
    private static String encode(String value) throws Exception {
        return URLEncoder.encode(value, "UTF-8");
    }

    /**
     * 从文件中获取字节
     *
     * @param f f
     * @return {@link byte[]}
     */
    public static byte[] getBytesFromFile(File f) {
        if (f == null) {
            return null;
        }
        try {
            FileInputStream stream = new FileInputStream(f);
            ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = stream.read(b)) != -1)
                out.write(b, 0, n);
            stream.close();
            out.close();
            return out.toByteArray();
        } catch (IOException e) {
        }
        return null;
    }

    /**
     * 提取信心
     *
     * @param responseBody 响应体
     * @param param        参数
     * @return {@link Object}
     */
    public static Object extractConfidence(String responseBody, String param) {
        JSONObject jsonObject = new JSONObject(responseBody);
        System.out.println(jsonObject);
        if (jsonObject.has(param)) {
            return jsonObject.get(param);
        } else if (jsonObject.has("results")) {
            JSONArray results = jsonObject.getJSONArray("results");
            JSONObject firstResult = results.getJSONObject(0);
            Object confidence = firstResult.get(param);
            System.out.println(confidence + "数据");
            if (Objects.equals(confidence, "") || Objects.equals(confidence, "[]")) {
                return null;
            } else
                return confidence;
        } else {
            return null;
        }

    }

    /**
     * 获取faceset令牌
     *
     * @return {@link String}
     */
    public String getFACESET_TOKEN() {
        return FACESET_TOKEN;
    }

    /**
     * 设置faceset令牌
     *
     * @param FACESET_TOKEN faceset令牌
     */
    public void setFACESET_TOKEN(String FACESET_TOKEN) {
        this.FACESET_TOKEN = FACESET_TOKEN;
    }

    /**
     * 检测人脸
     *
     * @param bytes 字节
     * @return {@link String}
     * @throws Exception 异常
     */
    @Override
    public String detectFace(byte[] bytes) throws Exception {
        String url = "https://api-cn.faceplusplus.com/facepp/v3/detect";
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, byte[]> byteMap = new HashMap<>();
        map.put("api_key", "7Qd7y5LflV5udF7sVgS01MPzNLgeuTWA");
        map.put("api_secret", "jTxK14YcqHlLWdepWnnomTbzh_OkZGtc");
        map.put("return_landmark", "1");
        map.put("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
        byteMap.put("image_file", bytes);
        try {
            byte[] bacd = post(url, map, byteMap);
            String str = new String(bacd);
            return str;
        } catch (Exception e) {
            e.printStackTrace();
            return "检测面部失败！";
        }
    }

  /*  *//**
     * 将面添加到库
     *
     * @param imageData 图像数据
     * @param stuToken  斯图令牌
     * @return {@link String}
     */
  /*
    @Override
    public String addFaceToLibrary(byte[] imageData, String stuToken) {
        String url = " https://api-cn.faceplusplus.com/facepp/v3/faceset/addface";
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, byte[]> byteMap = new HashMap<>();
        map.put("api_key", API_KEY);
        map.put("api_secret", API_SECRET);
        map.put("faceset_token", FACESET_TOKEN);
        map.put("face_tokens", stuToken);
        byteMap.put("image_file", imageData);
        try {
            byte[] bacd = post(url, map, byteMap);
            String str = new String(bacd);
            System.out.println(str);
            return str;
        } catch (Exception e) {
            e.printStackTrace();
            return "失败";
        }
    }*/

    /**
     * 将输入流转换为字符串
     *
     * @param inputStream 输入流
     * @return {@link String}
     * @throws IOException ioexception
     */
    private String convertInputStreamToString(InputStream inputStream) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 比对面然后比对是否匹配
     *
     * @param faceToken 检测出的人脸
     * @param sqlFaceToken 数据库的人脸
     * @return boolean
     */
    @Override
    public boolean searchFace( String faceToken,String sqlFaceToken) throws Exception {
        String url = "https://api-cn.faceplusplus.com/facepp/v3/compare";
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, byte[]> byteMap = new HashMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
        requestBody.add("api_key", API_KEY);
        requestBody.add("api_secret", API_SECRET);
        requestBody.add("face_token1", faceToken);
        requestBody.add("face_token2", faceToken);


        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

        if (response.getStatusCode() == HttpStatus.OK) {
            String responseBody = response.getBody();
            System.out.println(responseBody);
            // 解析响应数据，获取相似度信息
            if (Objects.isNull(responseBody)) {
                return false;
            }
                double confidence = (double) extractConfidence(responseBody, "confidence");
                System.out.println(confidence);
                return confidence > 80.0;
        } else {
            return false;
        }

    }

    /**
     * 添加消费者脸到数据库
     *
     * @param consumer 消费者
     * @return int
     */
    @Override
    public int addConsumerFace(FaceRecognitionRequest consumer) {
        return consumerMapper.addConsumerFace(consumer);
    }


}